package net.mof.manual

import com.squareup.javapoet.*
import net.mof.manual.Utils.custom_packageName
import net.mof.manual.Utils.file_comment
import net.mof.manual.Utils.stringClassName
import net.mof.manual.meta.BaseFieldMetaInfo
import javax.lang.model.element.Modifier

/**
 * 被JsonMark标记的类
 *
 * Created by LiYueHui on 2020/2/2.
 */
class MarkedClass {

    companion object {
        const val field_map = "__map__"
    }

    var packageName: String? = null
    var markedClassInfo: MarkedClassInfo? = null
    var baseFieldList: MutableList<BaseFieldMetaInfo> = ArrayList()
    var superMarkedClass: MarkedClass? = null
    var subTypeMap: MutableMap<String, TypeName> = HashMap()

    /**
     *   根据json注解，生成class文件
     * */
    fun brewMarkedClass(): JavaFile {
        val thisClassName = ClassName.get(packageName,
                markedClassInfo?.getClassName())

        val builder = TypeSpec
                .classBuilder(markedClassInfo?.getClassName_with_dollar() + "_json")
                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                .addSuperinterface(
                        ParameterizedTypeName.get(ClassName.get(
                                custom_packageName, "ITransformJson"),
                                thisClassName))
        val jsonBeanBrew = MarkedClassBrew()
        addStatic(builder)
        builder.addMethod(jsonBeanBrew.createTypeToJSONObject(this,
                thisClassName))
        builder.addMethod(jsonBeanBrew.createJsonToType(this, thisClassName))

        return JavaFile
                .builder(packageName, builder.build())
                .addFileComment(
                        file_comment)
                .build()
    }

    private fun addStatic(builder: TypeSpec.Builder) {
        if (!subTypeMap.isEmpty()) {
            val wildcard = WildcardTypeName.subtypeOf(ClassName.get(packageName,
                    markedClassInfo?.getClassName()));
            val mapClass = ParameterizedTypeName
                    .get(ClassName.get(HashMap::class.java),
                            stringClassName,
                            ParameterizedTypeName.get(ClassName.get(Class::class.java), wildcard))
            builder.addField(FieldSpec
                    .builder(mapClass, field_map)
                    .addModifiers(Modifier.STATIC).build())
            val codeBuidler = CodeBlock.builder()
            codeBuidler.addStatement(" \$L = new \$T()", field_map, mapClass)
            subTypeMap.forEach { (s: String?, typeName: TypeName?) ->
                codeBuidler.addStatement(
                        "\$L.put(\$S,\$T.class)", field_map, s, typeName)
            }
            builder.addStaticBlock(codeBuidler.build())
        }
    }

}